package com.note.common.utils;

import jakarta.annotation.PostConstruct;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.stereotype.Component;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;

import java.util.concurrent.TimeUnit;

/**
 * Redis工具类
 * 用于处理Redis缓存相关操作
 * 支持RedisTemplate和Jedis两种方式操作Redis
 */
@Slf4j
@Component
public class RedisUtils {

    /**
     * 用户token缓存前缀
     */
    public static final String TOKEN_PREFIX = "note:user:token:";

    /**
     * 用户信息缓存前缀
     */
    public static final String USER_INFO_PREFIX = "note:user:info:";

    /**
     * 默认缓存过期时间（秒）
     */
    public static final long DEFAULT_EXPIRE = 24 * 60 * 60; // 1天

    /**
     * 验证码缓存前缀
     */
    public static final String VERIFICATION_CODE_PREFIX = "note:verification:code:";

    /**
     * 验证码默认过期时间（秒）
     */
    public static final long VERIFICATION_CODE_EXPIRE = 5 * 60; // 5分钟

    /**
     * 静态实例，方便其他类直接调用
     */
    @Getter
    private static RedisUtils redisUtils;

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Autowired
    private JedisPool jedisPool;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    private static final String TOKEN_KEY_PREFIX = "token:user:";
    private static final String MSG_ID_KEY_PREFIX = "sms:msgid:";

    /**
     * 执行初始化的方法，并且只会被执行一次
     */
    @PostConstruct
    public void init() {
        redisUtils = this;
        redisUtils.redisTemplate = this.redisTemplate;
        // 设置值（value）的序列化采用StringRedisSerializer。 Jackson2JsonRedisSerializer时会带双引号
        redisTemplate.setValueSerializer(new StringRedisSerializer());
        redisTemplate.setHashValueSerializer(new StringRedisSerializer());
        // 设置键（key）的序列化采用StringRedisSerializer。
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
    }

    /**
     * 设置缓存 (使用RedisTemplate)
     *
     * @param key   缓存键
     * @param value 缓存值
     */
    public void set(String key, Object value) {
        try {
            redisTemplate.opsForValue().set(key, value);
        } catch (Exception e) {
            log.error("Redis设置缓存异常: key={}, value={}, error={}", key, value, e.getMessage(), e);
        }
    }

    /**
     * 设置缓存并设置过期时间 (使用RedisTemplate)
     *
     * @param key     缓存键
     * @param value   缓存值
     * @param timeout 过期时间（秒）
     */
    public void set(String key, Object value, long timeout) {
        try {
            redisTemplate.opsForValue().set(key, value, timeout, TimeUnit.SECONDS);
        } catch (Exception e) {
            log.error("Redis设置带过期时间的缓存异常: key={}, value={}, timeout={}, error={}",
                    key, value, timeout, e.getMessage(), e);
        }
    }

    /**
     * 设置缓存 (使用Jedis)
     *
     * @param key   缓存键
     * @param value 缓存值
     */
    public void setByJedis(String key, Object value) {
        try (Jedis jedis = jedisPool.getResource()) {
            jedis.set(key, String.valueOf(value));
        } catch (Exception e) {
            log.error("Jedis设置缓存异常: key={}, value={}, error={}", key, value, e.getMessage(), e);
        }
    }

    /**
     * 获取缓存 (使用RedisTemplate)
     *
     * @param key 缓存键
     * @return 缓存值
     */
    public Object get(String key) {
        try {
            return redisTemplate.opsForValue().get(key);
        } catch (Exception e) {
            log.error("Redis获取缓存异常: key={}, error={}", key, e.getMessage(), e);
            return null;
        }
    }

    /**
     * 获取缓存 (使用Jedis)
     *
     * @param key 缓存键
     * @return 缓存值
     */
    public String getByJedis(String key) {
        try (Jedis jedis = jedisPool.getResource()) {
            return jedis.get(key);
        } catch (Exception e) {
            log.error("Jedis获取缓存异常: key={}, error={}", key, e.getMessage(), e);
            return null;
        }
    }

    /**
     * 删除缓存 (使用RedisTemplate)
     *
     * @param key 缓存键
     */
    public void delete(String key) {
        try {
            redisTemplate.delete(key);
        } catch (Exception e) {
            log.error("Redis删除缓存异常: key={}, error={}", key, e.getMessage(), e);
        }
    }

    /**
     * 删除缓存 (使用Jedis)
     *
     * @param key 缓存键
     * @return 删除结果
     */
    public Long deleteByJedis(String key) {
        try (Jedis jedis = jedisPool.getResource()) {
            return jedis.del(key);
        } catch (Exception e) {
            log.error("Jedis删除缓存异常: key={}, error={}", key, e.getMessage(), e);
            return -1L;
        }
    }

    /**
     * 判断缓存是否存在 (使用RedisTemplate)
     *
     * @param key 缓存键
     * @return 是否存在
     */
    public boolean hasKey(String key) {
        try {
            return Boolean.TRUE.equals(redisTemplate.hasKey(key));
        } catch (Exception e) {
            log.error("Redis判断缓存是否存在异常: key={}, error={}", key, e.getMessage(), e);
            return false;
        }
    }

    /**
     * 判断缓存是否存在 (使用Jedis)
     *
     * @param key 缓存键
     * @return 是否存在
     */
    public boolean existsByJedis(String key) {
        try (Jedis jedis = jedisPool.getResource()) {
            return jedis.exists(key);
        } catch (Exception e) {
            log.error("Jedis判断缓存是否存在异常: key={}, error={}", key, e.getMessage(), e);
            return false;
        }
    }

    /**
     * 设置缓存过期时间 (使用RedisTemplate)
     *
     * @param key     缓存键
     * @param timeout 过期时间（秒）
     */
    public void expire(String key, long timeout) {
        try {
            redisTemplate.expire(key, timeout, TimeUnit.SECONDS);
        } catch (Exception e) {
            log.error("Redis设置缓存过期时间异常: key={}, timeout={}, error={}",
                    key, timeout, e.getMessage(), e);
        }
    }

    /**
     * 设置缓存过期时间 (使用Jedis)
     *
     * @param key     缓存键
     * @param timeout 过期时间（秒）
     * @return 结果
     */
    public Long expireByJedis(String key, long timeout) {
        try (Jedis jedis = jedisPool.getResource()) {
            return jedis.expire(key, timeout);
        } catch (Exception e) {
            log.error("Jedis设置缓存过期时间异常: key={}, timeout={}, error={}",
                    key, timeout, e.getMessage(), e);
            return -1L;
        }
    }

    /**
     * 缓存用户Token
     *
     * @param userId 用户ID
     * @param token  用户Token
     */
    public void setUserToken(Long userId, String token) {
        if (userId == null || token == null) {
            return;
        }
        String key = TOKEN_KEY_PREFIX + userId;
        redisTemplate.opsForValue().set(key, token, 24, TimeUnit.HOURS);
    }

    /**
     * 获取用户Token
     *
     * @param userId 用户ID
     * @return 用户Token
     */
    public String getUserToken(Long userId) {
        if (userId == null) {
            return null;
        }
        String key = TOKEN_KEY_PREFIX + userId;
        return (String) redisTemplate.opsForValue().get(key);
    }

    /**
     * 缓存用户信息
     *
     * @param userId   用户ID
     * @param userInfo 用户信息
     */
    public void setUserInfo(Long userId, Object userInfo) {
        set(USER_INFO_PREFIX + userId, userInfo, DEFAULT_EXPIRE);
    }

    /**
     * 获取用户信息
     *
     * @param userId 用户ID
     * @return 用户信息
     */
    public Object getUserInfo(Long userId) {
        return get(USER_INFO_PREFIX + userId);
    }

    /**
     * 删除用户信息缓存
     *
     * @param userId 用户ID
     */
    public void deleteUserInfo(Long userId) {
        delete(USER_INFO_PREFIX + userId);
    }

    /**
     * 删除用户Token缓存
     *
     * @param userId 用户ID
     */
    public void deleteUserToken(Long userId) {
        if (userId == null) {
            return;
        }
        String key = TOKEN_KEY_PREFIX + userId;
        redisTemplate.delete(key);
    }

    /**
     * 缓存验证码
     *
     * @param mobile 手机号
     * @param type   验证码类型 LOGIN/REGISTER/PASSWORD_RESET
     * @param code   验证码
     */
    public void setVerificationCode(String mobile, String type, String code) {
        set(VERIFICATION_CODE_PREFIX + type + ":" + mobile, code, VERIFICATION_CODE_EXPIRE);
    }

    /**
     * 获取验证码
     *
     * @param mobile 手机号
     * @param type   验证码类型 LOGIN/REGISTER/PASSWORD_RESET
     * @return 验证码
     */
    public String getVerificationCode(String mobile, String type) {
        Object code = get(VERIFICATION_CODE_PREFIX + type + ":" + mobile);
        return code != null ? code.toString() : null;
    }

    /**
     * 验证并删除验证码
     *
     * @param mobile    手机号
     * @param type      验证码类型 LOGIN/REGISTER/PASSWORD_RESET
     * @param inputCode 用户输入的验证码
     * @return 是否验证成功
     */
    public boolean verifyAndDeleteCode(String mobile, String type, String inputCode) {
        String key = VERIFICATION_CODE_PREFIX + type + ":" + mobile;
        Object code = get(key);

        if (code != null && code.toString().equals(inputCode)) {
            delete(key);
            return true;
        }
        return false;
    }

    /**
     * 删除验证码
     *
     * @param mobile 手机号
     * @param type   验证码类型 LOGIN/REGISTER/PASSWORD_RESET
     */
    public void deleteVerificationCode(String mobile, String type) {
        delete(VERIFICATION_CODE_PREFIX + type + ":" + mobile);
    }

    /**
     * 存储极光短信消息ID和手机号的关联
     *
     * @param mobile 手机号
     * @param type   验证码类型
     * @param msgId  极光消息ID
     */
    public void storeMsgId(String mobile, String type, String msgId) {
        if (mobile == null || type == null || msgId == null) {
            return;
        }
        String key = MSG_ID_KEY_PREFIX + mobile + ":" + type;
        redisTemplate.opsForValue().set(key, msgId, 5, TimeUnit.MINUTES);
    }

    /**
     * 获取存储的消息ID
     *
     * @param mobile 手机号
     * @param type   验证码类型
     * @return 消息ID，不存在返回null
     */
    public String getMsgId(String mobile, String type) {
        if (mobile == null || type == null) {
            return null;
        }
        String key = MSG_ID_KEY_PREFIX + mobile + ":" + type;
        return (String) redisTemplate.opsForValue().get(key);
    }

    /**
     * 删除存储的消息ID
     *
     * @param mobile 手机号
     * @param type   验证码类型
     */
    public void deleteMsgId(String mobile, String type) {
        if (mobile == null || type == null) {
            return;
        }
        String key = MSG_ID_KEY_PREFIX + mobile + ":" + type;
        redisTemplate.delete(key);
    }
} 